
// Copyright (c) 2020 InCore Semiconductors Pvt. Ltd. see LICENSE.incore for more details on licensing terms
/*
Author: Neel Gala, neelgala@incoresemi.com
Created on: Monday 04 May 2020 10:33:32 PM IST

*/
package TbDebugSoc ;
  import FIFOF        :: * ;
  import Vector       :: * ;
  import SpecialFIFOs :: * ;
  import FIFOF        :: * ;
  import Clocks       :: * ;
  import uart         :: * ;
  import ccore_types  :: * ;
  import GetPut       :: * ;
  import DCBus        :: * ;
  import DReg         :: * ;
  import axi4         :: * ;
  import ram2rw       :: * ;
  import Connectable  :: * ;
  import qspi         :: * ;
  import gpio         :: * ;
  import pwm          :: * ;
  import spi          :: * ;
  import axi4l        :: * ;
  import mem_config   :: * ;
//  import bsvmkissiflashwrapper :: * ;
  import TriState     :: * ;

  `include "Logger.bsv"
  `include "Soc_map.bsv"
  import DebugSoc     :: * ;

  import "BDPI" function ActionValue #(int) init_rbb_jtag(Bit#(1) dummy);
  import "BDPI" function ActionValue #(Bit #(8))get_frame(int client_fd);
  import "BDPI" function Action send_tdo(Bit #(1) tdo , int client_fd);

  (*synthesize*)
  module mkTbDebugSoc(Empty);

    let def_clk <- exposeCurrentClock;
    let def_rst <- exposeCurrentReset;

    MakeClockIfc#(Bit#(1)) tck_clk <-mkUngatedClock(1);
    MakeResetIfc trst <- mkReset(0,False,tck_clk.new_clk);

    Ifc_ram2rw_axi4#(`AXI4ID, `paddr, 64, `User, 4194304 , 64, 1 ) ddr_mem <-
                                                    mk_ram2rw_axi4(`DDRBase,
                                                    replicate(tagged File "ddr.mem"),"nc");
    Ifc_axi4_slave   #(`AXI4ID,`paddr, 64, `User) axi4_err    <- mkaxi4_err_2;
    Ifc_DebugSoc soc <- mkDebugSoc(tck_clk.new_clk, trst.new_rst);
    Ifc_axi4l_slave#(`paddr, 32, `User) axi4l_err    <- mkaxi4l_err_2;
    IWithDCBus#(DCBus#(`paddr,32), Ifc_uart#(16)) uart <- mkuart_block(5);
//    Ifc_issiflashwrapper flash <- mkissiflashwrapper();
		TriState#(Bit#(1)) tri_sio0 <- mkTriState(soc.qspi_io.io_enable[0] ==0,
                                          	 soc.qspi_io.io_o[0]);
		TriState#(Bit#(1)) tri_sio1 <- mkTriState(soc.qspi_io.io_enable[1] ==0,
                                          	 soc.qspi_io.io_o[1]);
		TriState#(Bit#(1)) tri_sio2 <- mkTriState(soc.qspi_io.io_enable[2] ==0,
                                          	 soc.qspi_io.io_o[2]);
		TriState#(Bit#(1)) tri_sio3 <- mkTriState(soc.qspi_io.io_enable[3] ==0,
                                          	 soc.qspi_io.io_o[3]);

    Reg#(Bool) rg_read_rx<- mkDReg(False);
    Reg#(Bit#(5)) rg_cnt <-mkReg(0);

    Wire#(Bool) wr_connect_ocd <- mkWire();

    Wire#(Bit#(1)) eth_int <- mkWire();
    mkConnection(ddr_mem.slave,soc.ddr_slave);
    mkConnection(soc.open_slave, axi4_err);
    mkConnection(soc.eth_slave, axi4l_err);
    mkConnection(soc.ma_eth_inp, eth_int);
//    mkConnection(tri_sio0.io, flash.si);
//    mkConnection(tri_sio1.io, flash.so);
//    mkConnection(tri_sio2.io, flash.wp);
//    mkConnection(tri_sio3.io, flash.sio3);
//
//    /*doc:rule: */
//    rule rl_connect_qspi_signals;
//      flash.isclk(soc.qspi_io.clk_o);
//      flash.ics(soc.qspi_io.ncs_o);
//    endrule:rl_connect_qspi_signals

    rule rl_connect_qspi_in;
      soc.qspi_io.io_i({tri_sio3._read, tri_sio2._read, tri_sio1._read, tri_sio0._read});
    endrule:rl_connect_qspi_in

    /*doc:rule: */
    rule rl_connect_bootconfig;
      let boot0 <- $test$plusargs("boot0");
      let boot1 <- $test$plusargs("boot1");
      let boot2 <- $test$plusargs("boot2");
      Bit#(2) boot_config = 0;
      if (boot1) boot_config = 'd1;
      if (boot2) boot_config = 'd2;
      soc.boot_config(boot_config);
      let _time <- $stime;
      if (_time < 120)
        $display("Boot Mode: %d",boot_config);
    endrule:rl_connect_bootconfig

    /*doc:rule: */
    rule rl_connect_ocd;
      let ocd_connect <- $test$plusargs("openocd");
      wr_connect_ocd <= ocd_connect;
    endrule

  `ifdef rtldump
 	  let dump <- mkReg(InvalidFile) ;
    rule rl_open_file_rtldump(rg_cnt<1);
      let generate_dump <- $test$plusargs("rtldump");
      if(generate_dump) begin
        String dumpFile = "rtl.dump" ;
    	  File lfh <- $fopen( dumpFile, "w" ) ;
    	  if ( lfh == InvalidFile )begin
    	    `logLevel( tb, 0, $format("TB: cannot open %s", dumpFile))
    	    $finish(0);
    	  end
    	  dump <= lfh ;
      end
    endrule:rl_open_file_rtldump
  `endif

 	  let dump1 <- mkReg(InvalidFile) ;
    rule rl_open_file_app(rg_cnt<1);
      String dumpFile1 = "app_log" ;
    	File lfh1 <- $fopen( dumpFile1, "w" ) ;
    	if (lfh1==InvalidFile )begin
    	  `logLevel( tb, 0, $format("TB: cannot open %s", dumpFile1))
    	  $finish(0);
    	end
      dump1 <= lfh1;
    	rg_cnt <= rg_cnt+1 ;
    endrule:rl_open_file_app

    rule rl_connect_uart_out;
      soc.ifc_uart0.sin(uart.device.io.sout);
    endrule:rl_connect_uart_out

    rule rl_connect_uart_in;
      uart.device.io.sin(soc.ifc_uart0.sout);
    endrule:rl_connect_uart_in

    rule rl_check_if_character_present(!rg_read_rx);
      let {err, data}<- uart.dcbus.read('hc,Sz1);
      if (data[3]==1) // character present
        rg_read_rx<=True;
    endrule:rl_check_if_character_present

    rule rl_write_received_character(rg_cnt>=1 && rg_read_rx);
      let {err,data}<-uart.dcbus.read('h8,Sz1);
      $fwrite(dump1,"%c",data);
    endrule:rl_write_received_character

    rule rl_connect_gpio;
      soc.ifc_gpio.gpio_in_val(replicate(0));
    endrule:rl_connect_gpio

    rule rl_drive_spi;
      soc.ifc_spi0.cipo.in(0);
      soc.ifc_spi0.copi.in(0);
      soc.ifc_spi0.ncs.in(0);
      soc.ifc_spi0.sclk.in(0);
      soc.ifc_spi1.cipo.in(0);
      soc.ifc_spi1.copi.in(0);
      soc.ifc_spi1.ncs.in(0);
      soc.ifc_spi1.sclk.in(0);
      soc.ifc_spi2.cipo.in(0);
      soc.ifc_spi2.copi.in(0);
      soc.ifc_spi2.ncs.in(0);
      soc.ifc_spi2.sclk.in(0);
    endrule:rl_drive_spi

  `ifdef rtldump
    rule rl_write_dump_file(rg_cnt>=1);
      let generate_dump <- $test$plusargs("rtldump");
      let {prv, pc, instruction, rd, data, rdtype}<- soc.io_dump.get;
      if( !wr_connect_ocd && (instruction=='h00006f||instruction =='h00a001))
        $finish(0);
      else if(generate_dump)begin
      	$fwrite(dump, prv, " 0x%16h", pc, " (0x%8h", instruction, ")");
        if(rdtype == FRF && valueOf(FLEN) == 64)
      	  $fwrite(dump, " f%d", rd, " 0x%16h", data[63:0], "\n");
        else if(rdtype == FRF && valueOf(FLEN) == 32)
      	  $fwrite(dump, " f%d", rd, " 0x%8h", data[31:0], "\n");
        else if(rdtype == IRF && valueOf(XLEN) == 64)
    	    $fwrite(dump, " x%d", rd, " 0x%16h", data[63:0], "\n");
        else if(rdtype == IRF && valueOf(XLEN) == 32)
    	    $fwrite(dump, " x%d", rd, " 0x%8h", data[31:0], "\n");
      end
    endrule:rl_write_dump_file
  `endif

  `ifdef debug
    Wire#(Bit#(1)) wr_tdi <-mkWire();
    Wire#(Bit#(1)) wr_tms <-mkWire();
    rule rl_connect_jtag_io;
      soc.wire_tdi(wr_tdi);
      soc.wire_tms(wr_tms);
    endrule:rl_connect_jtag_io
  `endif
    Wire#(Bit#(1)) wr_tdo <-mkWire();
    Wire#(Bit#(1)) wr_tck <-mkWire();
    Wire#(Bit#(1)) wr_trst <-mkWire();
    rule rl_wr_tdo(wr_connect_ocd);
      wr_tdo <= soc.wire_tdo();
    endrule:rl_wr_tdo
    Reg#(Bit#(1)) rg_initial <- mkRegA(0);
    Reg#(Bit#(1)) rg_end_sim <- mkRegA(0);
    Reg#(int) rg_client_fd <- mkRegA(32'hffffffff);
    Reg#(Bit#(5)) delayed_actor <- mkReg(0);
    Reg#(Bit#(5)) delayed_actor2 <- mkReg(0);
    Reg#(Bit#(5)) delayed_actor3 <- mkReg(0);
    Reg#(Bit#(5)) delayed_actor4 <- mkReg(0);
    Reg#(Bit#(5)) delayed_actor5 <- mkReg(0);
    rule rl_initialize_rbb(rg_initial == 0 && wr_connect_ocd);
      let x <- init_rbb_jtag(0);
      if(x != 32'hffffffff)begin
        rg_initial <= 1'b1;
        rg_client_fd <= x;
      end
    endrule:rl_initialize_rbb

    rule rl_get_frame((rg_initial == 1'b1 && wr_connect_ocd));
      let x <- get_frame(rg_client_fd);
      delayed_actor <= truncate(x);
      delayed_actor2 <= delayed_actor;
      delayed_actor3 <= delayed_actor2;
      delayed_actor4 <= delayed_actor3;
      delayed_actor5 <= delayed_actor4;
      tck_clk.setClockValue(delayed_actor2[2]);
      if(delayed_actor2[4] == 1)
        trst.assertReset();
      if(delayed_actor5[3] == 1 )
        send_tdo(wr_tdo,rg_client_fd);
      wr_tdi <= delayed_actor[0];
      wr_tms <= delayed_actor[1];
      if( x[5] == 1)begin
        $display("OpenOcd Exit");
        $finish();
      end
    endrule:rl_get_frame
  endmodule
endpackage: TbDebugSoc

